/**
 * 
 */
package org.xserver.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.xserver.annotation.PerformanceLog;
import org.xserver.annotation.VisitorLog;

/**
 * @author jkonopka
 * 
 */
@Aspect
public class Logger {

	/**
	 * @param joinPoint {@link ProceedingJoinPoint}
	 * @param performanceLog {@link PerformanceLog}
	 * @return {@link Object}
	 * @throws Throwable error handling
	 */
	@Around("execution(* *(..)) && @annotation(performanceLog)")
	public Object logPerformance(final ProceedingJoinPoint joinPoint, final PerformanceLog performanceLog)
			throws Throwable {
		final long start = System.currentTimeMillis();
		final Object value = joinPoint.proceed();
		time(start, joinPoint);
		return value;
	}

	/**
	 * @param joinPoint {@link ProceedingJoinPoint}
	 * @param visitorLog {@link VisitorLog}
	 * @return {@link Object}
	 * @throws Throwable error handling
	 */
	@Around("execution(* *(..)) && @annotation(visitorLog)")
	public Object logVisitor(final ProceedingJoinPoint joinPoint, final VisitorLog visitorLog) throws Throwable {
		entering(joinPoint);
		final Object value = joinPoint.proceed();
		leaving(joinPoint);
		return value;
	}

	/**
	 * @param start
	 * @param joinPoint
	 */
	private void time(final long start, final ProceedingJoinPoint joinPoint) {
		getLog(joinPoint).info(getTimeMessage(start, joinPoint));
	}

	/**
	 * @param start
	 * @param joinPoint
	 * @return
	 */
	private String getTimeMessage(final long start, final ProceedingJoinPoint joinPoint) {
		return String.format("Es wurde %d Millisekunden in %s gebraucht.", (System.currentTimeMillis() - start),
				joinPoint.getSignature().toShortString());
	}

	/**
	 * @param joinPoint
	 */
	private void entering(final ProceedingJoinPoint joinPoint) {
		debug("entering", joinPoint);
	}

	/**
	 * @param joinPoint
	 */
	private void leaving(final ProceedingJoinPoint joinPoint) {
		debug("leaving", joinPoint);
	}

	/**
	 * @param value
	 * @param joinPoint
	 */
	private void debug(final String value, final ProceedingJoinPoint joinPoint) {
		if (isDebugEnable()) {
			getLog(joinPoint).debug(value + " " + joinPoint.getSignature().toShortString());
		}
	}

	/**
	 * @return
	 */
	private boolean isDebugEnable() {
		return "TEST".equals(System.getProperty("stage"));
	}

	/**
	 * @param joinPoint
	 * @return
	 */
	private org.apache.log4j.Logger getLog(final ProceedingJoinPoint joinPoint) {
		return org.apache.log4j.Logger.getLogger(joinPoint.getSignature().getDeclaringType());
	}

}
